/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package prototype.runtime.federate;

import hla.rti.ArrayIndexOutOfBounds;
import hla.rti.RTIexception;
import hla.rti.jlc.NullFederateAmbassador;
import hla.rti.EventRetractionHandle;
import hla.rti.LogicalTime;
import hla.rti.ReceivedInteraction;
import hla.rti.ReflectedAttributes;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import prototype.persistence.pojo.User;
import prototype.persistence.pojo.UserHasUnit;
import prototype.runtime.federate.interactions.Death;
import prototype.runtime.federate.interactions.Fire;
import prototype.runtime.interfaces.RuntimeUnit;
import prototype.runtime.porticoutils.PorticoUtils;

/**
 *
 * @author Server
 */
public class RuntimeUserFederateAmbassador extends NullFederateAmbassador {

    private boolean announced;
    private boolean readyToRun;
    private double federateTime = 0.0;
    private double federateLookahead = 1.0;
    private boolean regulating = false;
    private boolean constrained = false;
    private boolean advancing = false;
    private RuntimeUser federate;
    
    public RuntimeUserFederateAmbassador(RuntimeUser federate) {
        super();
        this.federate = federate;
    }

    //////////////////////////////////////////////////////////////////////////
    ////////////////////////// RTI Callback Methods //////////////////////////
    //////////////////////////////////////////////////////////////////////////
    @Override
    public void synchronizationPointRegistrationFailed(String label) {
        log("Failed to register sync point: " + label);
    }

    @Override
    public void synchronizationPointRegistrationSucceeded(String label) {
        log("Successfully registered sync point: " + label);
    }

    @Override
    public void announceSynchronizationPoint(String label, byte[] tag) {
        log("Synchronization point announced: " + label);
        if (label.equals(RuntimeUser.READY_TO_RUN)) {
            this.announced = true;
        }
    }

    @Override
    public void federationSynchronized(String label) {
        log("Synchronization point announced: " + label);
        if (label.equals(RuntimeUser.READY_TO_RUN)) {
            this.readyToRun = true;
        }
    }

    /**
     * The RTI has informed us that time regulation is now enabled.
     */
    @Override
    public void timeRegulationEnabled(LogicalTime theFederateTime) {
        this.federateTime = PorticoUtils.convertTime(theFederateTime);
        this.regulating = true;
    }

    @Override
    public void timeConstrainedEnabled(LogicalTime theFederateTime) {
        this.federateTime = PorticoUtils.convertTime(theFederateTime);
        this.constrained = true;
    }

    @Override
    public void timeAdvanceGrant(LogicalTime theTime) {
        this.federateTime = PorticoUtils.convertTime(theTime);
        this.advancing = false;
    }

    @Override
    public void discoverObjectInstance(int theObject,
            int theObjectClass,
            String objectName) {
        log("Discoverd Object: handle=" + theObject + ", classHandle="
                + theObjectClass + ", name=" + objectName);
    }

    @Override
    public void reflectAttributeValues(int theObject,
            ReflectedAttributes theAttributes,
            byte[] tag) {

        reflectAttributeValues(theObject, theAttributes, tag, null, null);
    }

    @Override
    public void reflectAttributeValues(int theObject,
            ReflectedAttributes theAttributes,
            byte[] tag,
            LogicalTime theTime,
            EventRetractionHandle retractionHandle) {
        //Not used in our simulation
    }

    @Override
    public void receiveInteraction(int interactionClass,
            ReceivedInteraction theInteraction,
            byte[] tag) {

        receiveInteraction(interactionClass, theInteraction, tag, null, null);
    }

    @Override
    public void receiveInteraction(int interactionClass,
            ReceivedInteraction theInteraction,
            byte[] tag,
            LogicalTime theTime,
            EventRetractionHandle eventRetractionHandle) {
        try {
            if (interactionClass == federate.getFireInteractionHandle()) {
                Fire f = new Fire(theInteraction);
                log("Fire interaction received.");
                Vector<Death> deaths = f.applyToUnit(federate.getRuntimeUnits());
                federate.deaths.addAll(deaths);
            } else if (interactionClass == federate.getDeathInteractionHandle()) {
                Death d = new Death(theInteraction);
                log("Death interaction received with id: " + d.getId());
                d.apply(federate.getScenario());
            }

        } catch (ArrayIndexOutOfBounds ex) {
        }
    }

    @Override
    public void removeObjectInstance(int theObject, byte[] userSuppliedTag) {
    }

    @Override
    public void removeObjectInstance(int theObject,
            byte[] userSuppliedTag,
            LogicalTime theTime,
            EventRetractionHandle retractionHandle) {
    }
    /*
     * PRIVATE FUNCTIONS
     */

    private void log(String message) {
        System.out.println("Ambassador of " + federate.getUser().getName() + ": " + message);
    }

    /*
     *  GETTERS AND SETTER
     */
    public boolean isAnnounced() {
        return announced;
    }

    public boolean isReadyToRun() {
        return readyToRun;
    }

    public boolean isAdvancing() {
        return advancing;
    }

    public boolean isConstrained() {
        return constrained;
    }

    public boolean isRegulating() {
        return regulating;
    }

    public double getFederateLookahead() {
        return federateLookahead;
    }

    public double getFederateTime() {
        return federateTime;
    }

    public void setAdvancing(boolean advancing) {
        this.advancing = advancing;
    }

    public void setRegulating(boolean regulating) {
        this.regulating = regulating;
    }
}
